#ifndef ARGUMENT_SEPARATOR_HPP__
#define ARGUMENT_SEPARATOR_HPP__

/**
 * \file argument_separator.hpp
 * contains the argument_separator class, which serves as the tokenizer function
 * for parsing instructions and execution signals
 */

namespace BMD
{

  /**
   * Tokenizes instruction and execution signals.
   * argument_separator recognizes two major token types:
   *  - symbols, any combination of characters except quotes, spaces, and commas
   *  - quoted strings, which use '\' as an escape character
   * Tokens are separated by any number of spaces and commas, except obviously
   * for quoted characters of that type.
   */
  class argument_separator
  {
  public:
    argument_separator() { }

    /** 
     * retrieves the next token, moving the token iterator forward.
     */
    template <typename InputIterator, typename Token>
    bool operator()(InputIterator& next,InputIterator end,Token& tok)
    {
      // move past any spaces
      tok = Token();
      
      // move up until we get something that's not a space or comma
      while ((*next == ' ' || *next == ',') && next != end)
        ++next;
      if (next == end)
        return false;
      
      // if the first element isn't a quote, we should just read until we hit a
      // space or a comma
      if (*next != '"')
      {
        while (*next != ' ' && *next != ',')
        {
          tok += *next;
          if (++next == end)
            return true;
        }
        return true;
      }
      
      // if it is a quotation, keep reading in until we hit a quote, while
      // taking always munching the character after the escape character
      tok += *next;
      ++next;
      while (next != end && *next != '"')
      {
        // if it's not an escape character, read it
        if (*next != '\\')
        {
          tok += *next;
          ++next;
          continue;
        }
        
        // if it is an escape character, read it and the next character, being
        // sure to avoid going over
        tok += *next;
        ++next;
        if (next == end)
          throw instruction_parse_error("last token is string with no end-quote");
        tok += *next;
        ++next;
      }
      
      // if we get here, our next character should be a quote
      // otherwise, we didn't finish the string
      if (next == end)
        throw instruction_parse_error("last token is string with no end-quote");
      
      tok += *next;
      ++next;
      return true;
    } 
    void reset() { }
  };
}

#endif

